Quand utiliser git lfs et comment ?

La commande git lfs a été introduite dans la version 1.8.2 de git. Par conséquent, pensez à mettre à jour votre outil git avant de vous lancer dans l'utilisation de git lfs

Comment installer git lfs ?

C'est très simple (2 commandes).

Vérifications en amont

  • Vous devez vérifier votre version de git installée :
git --version

=> Si elle est antérieure à la 1.8.2, vous devez mettre à jour git.

  • Vous pouvez également vérifier si git lfs n'est pas déjà installée :
git lfs --version

=> Si vous obtenez un numéro de version, vous n'avez rien à installer, c'est déjà prêt !

Installation

  • Ensuite, vous devez installer git lfs et le rendre fonctionnel avec git pour tous vos dépôts git qui en auraient besoin :
sudo apt install git-lfs
git lfs install

=> Sous windows, la mise à jour de l'outil git va automatiquement installer git lfs.

Quand utiliser git lfs ?

Les nouvelles commandes git lfs permettent de gérer plus rapidement le stockage de gros fichiers dans votre dépôt git (lfs = large file storage). Quand on parle de gros fichiers, disons qu'au delà de 25Mo, on peut parler de fichiers anormalement volumineux.

Rappelons que git est un gestionnaire de version de votre code source et qu'à ce titre, vous ne devriez jamais avoir de fichiers de code source atteignant 25Mo.

Mais il peut être judicieux, de temps en temps, d'ajouter dans votre dépôt :

  • une base de mini-exemples de fichiers en entrée de votre programme pour pouvoir tester une version. Si ce sont des images, des vidéos, ça peut vite grimper,
  • une base de mini-exemples de fichiers en sortie de votre programme pour pouvoir montrer les résultats d'une version,
  • de la documentation au format pdf ou autre, qui évolue au fil des versions et peut également atteindre rapidement plusieurs dizaines de Mo.

Vous pourriez, bien sûr, gérer ces cas particuliers par le wiki, par les pages ou par la génération de releases attachées à votre projet. Mais là n'est pas le propos (d'autres articles, un jour, pour expliquer cela).

Il y a évidemment plein d'autres cas où il est plus pertinent d'attacher ces gros fichiers directement dans le dépôt git (nous verrons quelques exemples après la définition des avantages un peu plus loin).

Grands principes de git lfs

  • Coté serveur, les gros fichiers envoyés dans le dépôt sont stockés sous forme de liens symboliques et ces fichiers sont réellement stockés ailleurs, sous forme d'objets, et généralement sur un espace de stockage dédié. Ceci a 2 intérêts :
    • ne pas alourdir votre dépôt distant par ces gros fichiers,
    • accélérer l'envoi / le rappatriement des gros fichiers (jusqu'à 8 fichiers peuvent être envoyés en parallèle avec git lfs pull et git lfs push),
  • Côté client, donc pour vous, c'est quasi transparent. Vous ne remarquerez aucun changement dans votre dossier de travail courant. Les changements apparaissent uniquement dans le dossier caché .git/ :
    • apparition d'un sous-dossier lfs/,
    • rappatriement des gros fichiers dans le sous-dossier lfs/objects/.

Avantages de git lfs pour le client

Lorsque vous faites un git clone d'un projet :

  • En mode git lfs, vous rappatriez en local, dans le dossier .git/lfs/objects/ :
    • uniquement les gros fichiers de la branche main (jamais ceux des autres branches),
    • uniquement les gros fichiers de la dernière version sur le serveur (si vous avez supprimé des gros fichiers lors d'un commit, ils ne seront pas rappatriés),
    • pour résumer :
      • le stric minimum, uniquement les gros fichiers nécessaires à la dernière version de la branche main.
  • En mode normal, vous rappatriez en local, dans le dossier .git/objects/ :
    • les fichiers de toutes les versions antérieures de la branche main (même ceux que vous aviez supprimé il y a très longtemps),
    • les fichiers de toutes les autres branches (même si vous n'avez pas demandé à changer de branche en local),
    • les fichiers de toutes les anciennes versions des autres branches,
    • pour résumer :
      • tous les fichiers déposés, un jour, dans le dépôt, quelle que soit la branche, même si les fichiers ne sont actuellement présents sur aucune branche.

=> Par conséquent, si vous stockez une base d'exemples qui diffère d'une release à l'autre (notamment, les résultats en sortie), alors il peut être judicieux d'ajouter ces fichiers via git lfs même s'ils sont très inférieurs à 25Mo afin qu'un clone ne récupère que le stric nécessaire à l'exécution de la dernière release (pas tous les résultats de toutes les releases, cela n'a aucun intérêt).

Pour cloner un projet utilisant git lfs, préférez la commande git lfs clone à la commande git clone. En effet, la commande git lfs clone est plus rapide car elle va :

  • utiliser git clone en désactivant le suivi des gros fichiers via git lfs,
  • puis utiliser git lfs pull pour rappatrier les gros fichiers en mode parallèle (jusqu'à 8 en même temps).

=> Vous obtiendrez le même résultat si vous utilisez l'ancienne commande git clone, ce sera juste plus long pour rappatrier les gros fichiers.

Inconvénients de git lfs pour le client

ça découle directement des avantages, lorsque vous faites un git checkout :

  • Pour changer de branche et travailler sur une autre branche :
    • si vous n'aviez jamais travaillé sur cette branche auparavant,
    • alors le premier changement de branche peut être plus long (rappatriement des gros fichiers manquants si non présents dans l'autre branche).
  • Pour revenir en arrière sur un ancien commit :
    • si vous n'aviez jamais travaillé sur ce commit auparavant,
    • alors le premier retour vers ce commit peut être plus long (rappatriement des gros fichiers manquants si supprimés dans la dernière version).

=> Dans tous les cas, ce sont des situations exceptionnelles et ponctuelles qui nécessitent, de fait, le rappatriement de ces gros fichiers pour mettre à jour le répertoire de travail courant.

Comment utiliser git lfs ?

Choix des fichiers à suivre

La première fois que vous souhaitez utiliser git lfs sur un dépôt, il faut :

  • indiquer la liste des fichiers que l'on souhaite envoyer comme gros fichiers via git lfs :
# pour sélectionner tous les fichiers qui portent l'extension 'pdf'
git lfs track "*.pdf"
# pour sélectionner tous les fichiers du dossier 'data_out'
git lfs track "data_out/*"
# pour sélectionner le fichier 'data_in/exemple1.tiff'
git lfs track "data_in/exemple1.tiff"

=> Cela va générer un fichier .gitattributes contenant cette liste exhaustive de fichiers (avec regexp associée).

  • puis ajouter ce fichier de paramétrage à votre liste de fichiers à suivre :
git add ".gitattributes"

=> Ceci afin que les fichiers sélectionnés soient bien envoyés via git lfs le moment venu (voir section suivante).

Si vous souhaitez vérifier le contenu du fichier .gitattributes, il suffit de saisir :

git lfs track

Envoi des nouveaux fichiers ajoutés

Il n'y a rien de particulier à faire, les commandes habituelles seront utilisées, à savoir : git status, git add, git commit et git push.

  • Pour voir la liste des fichiers qui ne sont pas encore inclus pour le prochain commit :
git status

=> Les fichiers non inclus pour le prochain commit apparaissent en rouge.

  • Pour ajouter les fichiers que l'on souhaite inclure au prochain commit :
git add "data_out/result_exemple1.png"
git add "documentation/userguide_v1.0.0.pdf"

=> Comme ces fichiers respectent la syntaxe des expressions régulières inclues dans le fichier .gitattributes et que ce fichier est bien en suivi de version (on a précédemment fait un git add dessus), alors ces deux fichiers seront suivis via git lfs.

  • Pour vérifier que ces fichiers sont bien suivis via git lfs :
git lfs ls-files

=> Cette commande renvoie la liste des fichiers qui sont suivis par git lfs (même ceux qui n'ont pas encore été committés !)

  • Pour effectuer le prochain commit :
git commit -m "ajout des résultats de l'ex 1 et du guide de l'utilisateur en v1.0.0 via git lfs"
  • Pour envoyer ce commit sur le serveur et les deux fichiers via git lfs :
git push

En espérant que ce tuto vous ait éclairé un peu.

Migration des anciens fichiers committés

Si vous utilisez git lfs sur un dépôt existant, seuls les nouveaux fichiers ajoutés via git add et correspondant à la syntaxe du fichier .gitattributes seront suivis via git lfs.

Les anciens commits ne seront pas affectés par la mise en place du fichier .gitattributes. Néanmoins, il est possible d'effectuer une migration du suivi de ces anciens fichiers pour qu'ils soient à présent suivis via git lfs.

  • Pour tester le processus de migration du suivi (sans rien modifier) :
git lfs migrate info --everything --include="*.pdf,data_out/*,data_in/exemple1.tiff"

=> L'option --everything est à utiliser pour effectuer le processus de migration sur toutes les branches du dépôt. Il faut également saisir l'ensemble des fichiers à migrer avec l'option --include car le fichier .gitattributes est ignoré lors de la migration.

  • Pour lancer le processus de migration du suivi (modification des anciens commits de toutes les branches) :
git lfs migrate import --everything --include="*.pdf,data_out/*,data_in/exemple1.tiff" --verbose

=> L'option --verbose est optionnelle mais peut être rassurante, notamment si le dépôt est grand (suivi du processus de migration). Attention, tous les commits modifiés (contenant finalement un suivi de fichier via git lfs) seront réécrits et donc porteront un nouveau SHA.

Nettoyage du dépôt local (sans perte de données)

En exécutant la commande :

git lfs prune --dry-run

Vous allez réduire l'espace utilisé pour votre dépôt local (suppression de fichiers dans .git/lfs/objects) en vérifiant que les fichiers supprimés :

  • ne sont présents ni dans le dossier de travail courant, ni dans l'espace des piles d'attente,
  • ne sont présents dans un commit récent ni de la branche courante, ni d'une branche récente,
  • ne sont présents dans aucun commit non poussé sur le serveur distant.

=> L'option --dry-run évite de supprimer directement ces fichiers mais fait juste un test et liste les fichiers qu'il souhaite effacer. On peut ajouter l'option --verify-remote -c afin de vérifier que les fichiers à supprimer sont bien tous présents sur le dépôt distant.

Nettoyage du dépôt distant (suppression de données)

Attention, c'est une opération très destructive et irréversible puisqu'elle consiste à réduire la taille du dépôt (suppression de fichiers devenus finalement inutiles dans le dépôt).

Il faut au préalable :

  • faire une copie intégrale de son projet en le récupérant sur le serveur (pour avoir une copie serveur avec toutes les refs),
  • puis travailler en local,
  • reconstruire le dépôt depuis la sauvegarde avec les options --bare --mirror de git clone.

Voici un lien sur gitlab qui vous explique ce qu'il est possible de faire.

L'outil ancestral est git filter-branch auquel on peut lui passer une commande comme rm -f nom_du_fichier_a_supprimer. Je ne détaillerai volontairement pas la méthode pour que vous preniez le temps de lire une documentation complète et que vous appreniez à vous servir de ce type de commande (utile aussi pour les fichiers suivis par la commande git classique, sans l'extension lfs).

Un outil plus récent est git filter-repo, plus rapide à utiliser mais il faut l'installer au préalable (voir le lien gitlab ci-dessus pour les refs).


Auteur : Bruno Mercier - Licence CC-BY-NC-SA-4.0